package com.example.lottery.service.activitystatus.impl;

import com.example.lottery.common.errorcode.ServiceErrorCodeConstants;
import com.example.lottery.common.exception.ServiceException;
import com.example.lottery.common.utils.RedisUtil;
import com.example.lottery.service.IActivityService;
import com.example.lottery.service.activitystatus.IActivityStatusManger;
import com.example.lottery.service.activitystatus.operator.AbstractOperator;
import com.example.lottery.service.dto.ConvertActivityStatusDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

@Slf4j
@Component
public class ActivityStatusMangerImpl implements IActivityStatusManger {

    @Autowired
    private IActivityService activityService;
    @Autowired
    private Map<String, AbstractOperator>operatorMap=new HashMap<>();
    /**
     * 处理状态扭转
     * @param convertActivityStatusDTO 状态扭转需要的参数
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void convertHandler(ConvertActivityStatusDTO convertActivityStatusDTO) {
        //使用map管理 用户、奖品、活动<String, AbstractOperator>
        if(operatorMap==null){
            log.warn("operatorMap为空");
            throw new ServiceException(ServiceErrorCodeConstants.DRAW_PRIZE_MAP_NOT_EXIST);
        }
        //避免operatorMap被改变
        Map<String, AbstractOperator>currentMap=new HashMap<>(operatorMap);

        boolean flag=false;
        //1-    用户、奖品扭转
        flag=processConvertStatus(1,convertActivityStatusDTO,currentMap);

        //2-    活动扭转
        flag=processConvertStatus(2,convertActivityStatusDTO,currentMap)||flag;

        //3-    更新缓存
        if(flag){
            //更新缓存
            activityService.updateCache(convertActivityStatusDTO.getActivityId());
        }
    }

    /**
     * 处理状态回滚 COMPLETE->INIT
     * @param convertActivityStatusDTO 状态回滚需要的参数
     */
    @Override
    public void rollbackConvertHandler(ConvertActivityStatusDTO convertActivityStatusDTO) {
        //走到这里，说明奖品回滚了，那么活动一定也需要回滚，活动奖品下的状态为INIT
        //使用map管理 用户、奖品、活动<String, AbstractOperator>
        if(operatorMap==null){
            log.warn("operatorMap为空");
            throw new ServiceException(ServiceErrorCodeConstants.DRAW_PRIZE_MAP_NOT_EXIST);
        }
        //直接遍历operatorMap，回滚状态没有先后顺序
        for(AbstractOperator abstractOperator:operatorMap.values()){
            abstractOperator.convertStatus(convertActivityStatusDTO);
        }
        //更改缓存信息 (从数据库中获取更新后的值然后存入redis)
        activityService.updateCache(convertActivityStatusDTO.getActivityId());
    }

    /**
     * 扭转
     * @param i 执行的顺序
     * @param convertActivityStatusDTO 扭转状态和判断是否需要扭转需要的参数
     * @param currentMap 管控的operator
     * @return
     */
    private boolean processConvertStatus(int i,
                                      ConvertActivityStatusDTO convertActivityStatusDTO,
                                      Map<String, AbstractOperator> currentMap) {

        Iterator<Map.Entry<String, AbstractOperator>> iterator = currentMap.entrySet().iterator();
        boolean flag=false;
        //1-    遍历currentMap
        while (iterator.hasNext()){
            AbstractOperator operator=iterator.next().getValue();
            //2-    判断sequence和i是否相同，相同就要执行
            //3-    还需要判断是否进行扭转
            if(!operator.sequence().equals(i)||!operator.needConvert(convertActivityStatusDTO)){
                //不需要扭转，遍历下一个
                continue;
            }
            //4-    需要扭转状态
            if(!operator.convertStatus(convertActivityStatusDTO)){
                //扭转状态失败
                log.warn("状态扭转失败 operator:{}",operator.getClass().getName());
                throw new ServiceException(ServiceErrorCodeConstants.DRAW_PRIZE_CONVERT_STATUS_ERROR);
            }
            //5-    将operator从map删除，避免下次调用又判断一次
            iterator.remove();
            flag=true;
        }
        return flag;
    }

}
